package org.train.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.train.util.R;
import org.train.util.RUtil;
import org.train.util.Renum;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig{
    // TODO 增加权限
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
        http.authorizeRequests()
                .antMatchers("/register").permitAll()
                //.anyRequest().authenticated()
                .anyRequest().permitAll()
                // 登录
                .and().formLogin()
                .successHandler(authenticationSuccessHandler) // 登入成功处理器
                .failureHandler(authenticationFailureHandler) // 登入失败处理器
                // 异常处理
                .and().logout()
                .permitAll()
                .logoutSuccessHandler(logoutSuccessHandler)
                .deleteCookies("JSESSIONID")
                .and().exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint) // 无权限资源时的异常处理
                // csrf
                .and().csrf().disable().cors();
        return http.build();
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    // 匿名用户访问无权限资源
    private final AuthenticationEntryPoint authenticationEntryPoint = new AuthenticationEntryPoint(){
        @Override
        public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException{
            response.setContentType("text/json;charset=utf-8");
            response.getWriter()
                    .write(objectMapper.writeValueAsString((RUtil.error(Renum.NOT_LOGIN))));
        }
    };

    // 登入成功处理器
    private final AuthenticationSuccessHandler authenticationSuccessHandler = new AuthenticationSuccessHandler(){
        @Override
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException{
            // 此处可以通过SecurityContextHolder.getContext().getAuthentication().getPrincipal()获取到当前用户，并进行一些操作

            response.setContentType("text/json;charset=utf-8");
            response.getWriter()
                    .write(objectMapper.writeValueAsString((RUtil.success())));
        }
    };

    // 登入失败处理器
    private final AuthenticationFailureHandler authenticationFailureHandler = new AuthenticationFailureHandler(){
        @Override
        public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException{
            R r;
            exception.printStackTrace();
            if(exception instanceof BadCredentialsException){
                // 密码错误
                r = RUtil.error(Renum.USER_CREDENTIALS_ERROR);
            }else if(exception instanceof UsernameNotFoundException){
                // 用户不存在
                r = RUtil.error(Renum.USER_ACCOUNT_NOT_EXIST);
            }else{
                // 其他错误
                r = RUtil.error(Renum.USER_LOGIN_COMMON_FAIL);
            }

            response.setContentType("text/json;charset=utf-8");
            response.getWriter()
                    .write(objectMapper.writeValueAsString(r));
        }
    };

    // 登出成功处理器
    private final LogoutSuccessHandler logoutSuccessHandler = new LogoutSuccessHandler(){
        @Override
        public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException{
            response.setContentType("text/json;charset=utf-8");
            response.getWriter()
                    .write(objectMapper.writeValueAsString(RUtil.success()));
        }
    };
}
